/**
 * PMXCrossover.java
 * Class representing a partially matched (PMX) crossover operator
 * @author Antonio J. Nebro
 * @version 1.0
 */
package jmetal.base.operator.crossover;

import TeamPursuit.MensTeamPursuit;
import TeamPursuit.SimulationResult;
import TeamPursuit.WomensTeamPursuit;
import P3.Strategy;
import java.util.ArrayList;
import java.util.Properties;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import jmetal.base.*;
import jmetal.base.variable.*;
import jmetal.util.Configuration;
import jmetal.util.JMException;
import jmetal.util.PseudoRandom;

/**
 * This class allows to apply a PMX crossover operator using two parent
 * solutions.
 * NOTE: the operator is applied to the first variable of the solutions, and
 * the type of those variables must be VariableType_.Permutation.
 */
public class MyCrossover extends Crossover {

    /**
     * Perform the crossover operation
     * @param probability Crossover probability
     * @param parent1 The first parent
     * @param parent2 The second parent
     * @return An array containig the two offsprings
     * @throws JMException
     */
    public Solution[] doCrossover(double probability,
            Solution parent1,
            Solution parent2) throws JMException {

        Solution[] offspring = new Solution[2];


        SimulationResult result = null;
        Random r = new Random();
        Strategy str1 = (Strategy) parent1.getDecisionVariables()[0].deepCopy();
        Strategy str2 = (Strategy) parent2.getDecisionVariables()[0].deepCopy();

        int power[] = new int[str1.getPower().length];
        boolean pacing[] = new boolean[str1.getPacing().length];

        if (r.nextDouble() <= probability)//do the transaction cross
        {
            for (int i = 0; i < 2; i++) {
                while ((result == null || !isValid(result))) {
                    Strategy str1copy = (Strategy) str1.deepCopy();
                    Strategy str2copy = (Strategy) str2.deepCopy();
                    power = cross(str1copy.getPower(), str2copy.getPower());
                    pacing = cross(str1copy.getPacing(), str2copy.getPacing());
                    try {
                        if (parent1.getType().typename.equalsIgnoreCase("men")) {
                            MensTeamPursuit teamPursuit = new MensTeamPursuit();
                            result = teamPursuit.simulate(pacing, power);
                        } else if (parent1.getType().typename.equalsIgnoreCase("women")) {
                            WomensTeamPursuit teamPursuit = new WomensTeamPursuit();
                            result = teamPursuit.simulate(pacing, power);
                        } else {
                            System.out.println("Error");
                            System.exit(-1);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }

                Strategy newStr = new Strategy(pacing, power);
                Variable[] var = new Variable[1];
                try {
                    offspring[i] = new Solution(parent1.getProblem());
                } catch (ClassNotFoundException ex) {
                    Logger.getLogger(MyCrossover.class.getName()).log(Level.SEVERE, null, ex);
                }
                var[0] = newStr;
                offspring[i].setDecisionVariables(var);
            }


        }

        // else
        return offspring;
    } // doCrossover

    private int[] cross(int[] a, int[] b) {
        Random r = new Random();
        int position = r.nextInt(a.length);
        int temp;
        for (int i = position; i < a.length; i++) {
            temp = a[i];
            a[i] = b[i];
            b[i] = temp;
        }

        return a;
    }

    private boolean[] cross(boolean[] a, boolean[] b) {
        Random r = new Random();
        int position = r.nextInt(a.length);
        boolean temp;
        for (int i = position; i < a.length; i++) {
            temp = a[i];
            a[i] = b[i];
            b[i] = temp;
        }
        return a;
    }

    /**
     * Executes the operation
     * @param object An object containing an array of two solutions
     * @throws JMException
     */
    public Object execute(Object object) throws JMException {
        Solution[] parents = (Solution[]) object;
        Double crossoverProbability = null;


        //crossoverProbability = (Double)parameters_.get("probability");
        crossoverProbability = (Double) getParameter("probability");

        if (parents.length < 2) {
            Configuration.logger_.severe("PMXCrossover.execute: operator needs two "
                    + "parents");
            Class cls = java.lang.String.class;
            String name = cls.getName();
            throw new JMException("Exception in " + name + ".execute()");
        } else if (crossoverProbability == null) {
            Configuration.logger_.severe("PMXCrossover.execute: probability not "
                    + "specified");
            Class cls = java.lang.String.class;
            String name = cls.getName();
            throw new JMException("Exception in " + name + ".execute()");
        }

        Solution[] offspring = doCrossover(crossoverProbability.doubleValue(),
                parents[0],
                parents[1]);

        return offspring;
    } // execute

    private boolean isValid(SimulationResult result) {
        if (result.getProportionCompleted() < 0.9999998) {
            return false;
        } else {
            return true;
        }
    }
} // PMXCrossover

